/**
 * chenuu.com
 * 
 * @author  zhaoxu.com@gmail.com
 * @created 2012-11-10
 */
package com.chenuu.integration.dropbox.model;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.json.simple.JSONArray;

import com.chenuu.common.utils.MapUtil;
import com.dropbox.client2.DropboxAPI.Entry;
import com.dropbox.client2.jsonextract.JsonExtractionException;
import com.dropbox.client2.jsonextract.JsonExtractor;
import com.dropbox.client2.jsonextract.JsonThing;

/**
 *
 */
public class DropboxEntry {
	/** Size of the file. */
    public long bytes;

    /**
     * If a directory, the hash is its "current version". If the hash
     * changes between calls, then one of the directory's immediate
     * children has changed.
     */
    public String hash;

    /**
     * Name of the icon to display for this entry. Corresponds to filenames
     * (without an extension) in the icon library available at
     * https://www.dropbox.com/static/images/dropbox-api-icons.zip.
     */
    public String icon;

    /** True if this entry is a directory, or false if it's a file. */
    public boolean isDir;

    /**
     * Last modified date, in "EEE, dd MMM yyyy kk:mm:ss ZZZZZ" form (see
     * {@code RESTUtility#parseDate(String)} for parsing this value.
     */
    public String modified;

    /**
     * For a file, this is the modification time set by the client when
     * the file was added to Dropbox.  Since this time is not verified (the
     * Dropbox server stores whatever the client sends up) this should only
     * be used for display purposes (such as sorting) and not, for example,
     * to determine if a file has changed or not.
     *
     * <p>
     * This is not set for folders.
     * </p>
     */
    public String clientMtime;

    /** Path to the file from the root. */
    public String path;

    /**
     * Name of the root, usually either "dropbox" or "app_folder".
     */
    public String root;

    /**
     * Human-readable (and localized, if possible) description of the
     * file size.
     */
    public String size;

    /** The file's MIME type. */
    public String mimeType;

    /**
     * Full unique ID for this file's revision. This is a string, and not
     * equivalent to the old revision integer.
     */
    public String rev;

    /** Whether a thumbnail for this is available. */
    public boolean thumbExists;

    /**
     * Whether this entry has been deleted but not removed from the
     * metadata yet. Most likely you'll only want to show entries with
     * isDeleted == false.
     */
    public boolean isDeleted;

    /** A list of immediate children if this is a directory. */
    public List<DropboxEntry> contents;

    /**
     * Creates an entry from a map, usually received from the metadata
     * call. It's unlikely you'll want to create these yourself.
     *
     * @param map the map representation of the JSON received from the
     *         metadata call, which should look like this:
     * <pre>
     * {
     *    "hash": "528dda36e3150ba28040052bbf1bfbd1",
     *    "thumb_exists": false,
     *    "bytes": 0,
     *    "modified": "Sat, 12 Jan 2008 23:10:10 +0000",
     *    "path": "/Public",
     *    "is_dir": true,
     *    "size": "0 bytes",
     *    "root": "dropbox",
     *    "contents": [
     *    {
     *        "thumb_exists": false,
     *        "bytes": 0,
     *        "modified": "Wed, 16 Jan 2008 09:11:59 +0000",
     *        "path": "/Public/\u2665asdas\u2665",
     *        "is_dir": true,
     *        "icon": "folder",
     *        "size": "0 bytes"
     *    },
     *    {
     *        "thumb_exists": false,
     *        "bytes": 4392763,
     *        "modified": "Thu, 15 Jan 2009 02:52:43 +0000",
     *        "path": "/Public/\u540d\u79f0\u672a\u8a2d\u5b9a\u30d5\u30a9\u30eb\u30c0.zip",
     *        "is_dir": false,
     *        "icon": "page_white_compressed",
     *        "size": "4.2MB"
     *    }
     *    ],
     *    "icon": "folder_public"
     * }
     * </pre>
     */
    @SuppressWarnings("unchecked")
    public DropboxEntry(Map<String, Object> map) {
        bytes = MapUtil.getLong(map, "bytes");
        hash = (String) map.get("hash");
        icon = (String) map.get("icon");
        isDir = MapUtil.getBoolean(map, "is_dir");
        modified = (String) map.get("modified");
        clientMtime = (String) map.get("client_mtime");
        path = (String) map.get("path");
        root = (String) map.get("root");
        size = (String) map.get("size");
        mimeType = (String) map.get("mime_type");
        rev = (String) map.get("rev");
        thumbExists = MapUtil.getBoolean(map, "thumb_exists");
        isDeleted = MapUtil.getBoolean(map, "is_deleted");

        Object json_contents = map.get("contents");
        if (json_contents != null && json_contents instanceof JSONArray) {
            contents = new ArrayList<DropboxEntry>();
            Object entry;
            Iterator<?> it = ((JSONArray) json_contents).iterator();
            while (it.hasNext()) {
                entry = it.next();
                if (entry instanceof Map) {
                    contents.add(new DropboxEntry((Map<String, Object>) entry));
                }
            }
        } else {
            contents = null;
        }
    }

    public DropboxEntry() {
    }

    /**
     * Returns the file name if this is a file (the part after the last
     * slash in the path).
     */
    public String fileName() {
        int ind = path.lastIndexOf('/');
        return path.substring(ind + 1, path.length());
    }

    /**
     * Returns the path of the parent directory if this is a file.
     */
    public String parentPath() {
        if (path.equals("/")) {
            return "";
        } else {
            int ind = path.lastIndexOf('/');
            return path.substring(0, ind + 1);
        }
    }

    public static final JsonExtractor<Entry> JsonExtractor = new JsonExtractor<Entry>() {
        public Entry extract(JsonThing jt) throws JsonExtractionException {
            return new Entry(jt.expectMap().internal);
        }
    };
}
